home *** CD-ROM | disk | FTP | other *** search
/ Multimedia Jumpstart / Multimedia Microsoft Jumpstart Version 1.1a (Microsoft).BIN / develpmt / source / midikeyb / testkeyb.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-09-12  |  19.8 KB  |  659 lines

  1. /*    (C) Copyright Microsoft Corp. 1991.  All rights reserved.
  2.  *
  3.  *    You have a royalty-free right to use, modify, reproduce and 
  4.  *    distribute the Sample Files (and/or any modified version) in 
  5.  *    any way you find useful, provided that you agree that 
  6.  *    Microsoft has no warranty obligations or liability for any 
  7.  *    Sample Application Files which are modified. 
  8.  */
  9.  
  10.  
  11. /** testkeyb.c
  12.  *
  13.  *  DESCRIPTION: 
  14.  *      This app is designed to show how to use the midiKeyB control in
  15.  *      your applications.  It doesn't do a whole lot--so you don't have
  16.  *      to wade through a bunch of code trying to figure out how to use
  17.  *      it.
  18.  *
  19.  *
  20.  **/
  21.  
  22.  
  23. /* the includes we need */
  24.     #include <windows.h>
  25.     #include <mmsystem.h>
  26.     #include <stdio.h>
  27.     #include <string.h>
  28.     #include "testkeyb.h"
  29.  
  30.  
  31. /* for debuggin' */
  32.     #ifdef DEBUG
  33.         #define D(x)    {x;}
  34.         #define ODS(x)  OutputDebugString(x)
  35.     #else
  36.         #define D(x)
  37.         #define ODS(x)
  38.     #endif
  39.  
  40.  
  41. /* I wonder why this isn't defined? */
  42.     #define MAKEWORD(bLow, bHigh)   ((WORD)((bHigh<<8)|bLow))
  43.  
  44.  
  45. /* prototypes for good measure */
  46.     long FAR PASCAL tkeybWndProc( HWND, WORD, WORD, LONG );
  47.     BOOL NEAR PASCAL tkeybSetKeyboardParameters( HWND hKeyB );
  48.     BOOL NEAR PASCAL tkeybAllNotesOff( HWND hKeyB );
  49.     void FAR PASCAL tkeybHourGlass( BOOL fHourGlass );
  50.  
  51.  
  52. /* globals, no less */
  53.     char        gszAppName[] = "midiKeyB Test Application";
  54.     char        gszShortName[] = "midiKeyB";
  55.     char        gachTemp[ 80 ];             /* temporary stuff...       */
  56.     HANDLE      ghInst;                     /* our instance handle      */
  57.     HWND        ghWnd;                      /* main window handle       */
  58.  
  59.     HWND        ghKeyB;                     /* midiKeyB control window  */
  60.     HMIDIOUT    ghMidiOut   =   NULL;       /* output MIDI device handle*/
  61.  
  62.     short       gnDevice    =   MIDIMAPPER; /* current device id        */
  63.     BYTE        gbChannel   =   0;          /* channel number (0 base)  */
  64.     BYTE        gbPatch     =   0;          /* current patch number     */
  65.     BYTE        gbVolume    =   100;        /* current key velocity     */
  66.  
  67.  
  68. /* control switches */
  69.     BOOL    gfLabelKeys     = FALSE;        /* put labels on keys?      */
  70.     BOOL    gfHideousColors = FALSE;        /* ...says it all.          */
  71.  
  72.  
  73. /** void FAR PASCAL tkeybHourGlass( BOOL fHourGlass )
  74.  *
  75.  *  DESCRIPTION: 
  76.  *      This function changes the cursor to that of the hour glass or
  77.  *      back to the previous cursor.
  78.  *
  79.  *  ARGUMENTS:
  80.  *      BOOL fHourGlass :   TRUE if we need the hour glass.  FALSE if
  81.  *                          we need the arrow back.
  82.  *
  83.  *  RETURN (void):
  84.  *      On return, the cursor will be what was requested.
  85.  *
  86.  *  NOTES:
  87.  *      This function can be called recursively.
  88.  *
  89.  **/
  90.  
  91. void FAR PASCAL tkeybHourGlass( BOOL fHourGlass )
  92. {
  93.     static HCURSOR  hCursor;
  94.     static WORD     wWaiting = 0;
  95.  
  96.     if ( fHourGlass )
  97.     {
  98.         if ( !wWaiting )
  99.         {
  100.             hCursor = SetCursor( LoadCursor( NULL, IDC_WAIT ) );
  101.             ShowCursor( TRUE );
  102.         }
  103.  
  104.         wWaiting++;
  105.     }
  106.  
  107.     else
  108.     {
  109.         if ( !--wWaiting )
  110.         {
  111.             ShowCursor( FALSE );
  112.             SetCursor( hCursor );
  113.         }
  114.     }
  115. } /* tkeybHourGlass() */
  116.  
  117.  
  118. /** BOOL FAR PASCAL tkeybAboutDlgProc( hDlg, wMsg, wParam, lParam )
  119.  *
  120.  *  DESCRIPTION: 
  121.  *      This is the dlg proc for the about box.
  122.  *
  123.  *  NOTES:
  124.  *
  125.  **/
  126.  
  127. BOOL FAR PASCAL tkeybAboutDlgProc( HWND   hDlg,
  128.                                    WORD   wMsg,
  129.                                    WORD   wParam,
  130.                                    LONG   lParam )
  131. {
  132.     switch ( wMsg )
  133.     {
  134.         case WM_INITDIALOG:
  135.             /* I want the focus on the ok button */
  136.             SetFocus( GetDlgItem( hDlg, IDOK ) );
  137.         break;
  138.  
  139.         case WM_COMMAND:
  140.             if ( (wParam == IDOK) || (wParam == IDCANCEL) )
  141.             {
  142.                 EndDialog( hDlg, TRUE );
  143.                 return ( TRUE );
  144.             }
  145.         break;
  146.     }
  147.  
  148.     return ( FALSE );
  149. } /* tkeybAboutDlgProc() */
  150.  
  151.  
  152. /** BOOL FAR PASCAL tkeybConfigDlgProc( hDlg, wMsg, wParam, lParam )
  153.  *
  154.  *  DESCRIPTION: 
  155.  *      This is the dlg proc for the configuration dlg box.
  156.  *
  157.  *  NOTES:
  158.  *
  159.  **/
  160.  
  161. BOOL FAR PASCAL tkeybConfigDlgProc( HWND   hDlg,
  162.                                     WORD   wMsg,
  163.                                     WORD   wParam,
  164.                                     LONG   lParam )
  165. {
  166.     static short    nVolume;
  167.     HWND            hCtrl;
  168.  
  169.     switch ( wMsg )
  170.     {
  171.         case WM_INITDIALOG:
  172.         {
  173.             MIDIOUTCAPS moc;
  174.             WORD        wNumDevs;
  175.  
  176.             /* fill in device combo box */
  177.             hCtrl = GetDlgItem( hDlg, IDD_CFG_DEVICE );
  178.  
  179.             /* put MIDI Mapper at index 0 */
  180.             wsprintf( gachTemp, "%s", (LPSTR)"MIDI Mapper" );
  181.             SendMessage( hCtrl, CB_ADDSTRING, 0, (LONG)(LPSTR)gachTemp );
  182.  
  183.             wNumDevs = midiOutGetNumDevs();
  184.             for ( wParam = 0; wParam < wNumDevs; wParam++ )
  185.             {
  186.                 SendMessage( hCtrl, CB_ADDSTRING, 0, 
  187.                     midiOutGetDevCaps(wParam, &moc, sizeof(moc)) ?
  188.                     (LONG)(LPSTR)"BOGUS!" : (LONG)(LPSTR)moc.szPname );
  189.             }
  190.  
  191.  
  192.             /* this assumes MIDIMAPPER == -1 and is index 0 in combo box */
  193.             SendMessage( hCtrl, CB_SETCURSEL, (gnDevice + 1), 0 );
  194.  
  195.  
  196.             /* fill in channel combo box */
  197.             hCtrl = GetDlgItem( hDlg, IDD_CFG_CHANNEL );
  198.             for ( wParam = 1; wParam <= 16; wParam++ )
  199.             {
  200.                 wsprintf( gachTemp, "%d", wParam );
  201.                 SendMessage( hCtrl, CB_ADDSTRING, 0, (LONG)(LPSTR)gachTemp );
  202.             }
  203.             SendMessage( hCtrl, CB_SETCURSEL, gbChannel, 0 );
  204.  
  205.  
  206.             /* set the volume gauge */
  207.             SetDlgItemInt( hDlg, IDD_CFG_VOLTEXT, gbVolume, FALSE );
  208.             hCtrl = GetDlgItem( hDlg, IDD_CFG_VOLUME );
  209.             SetScrollRange( hCtrl, SB_CTL, 0, 127, FALSE );
  210.             SetScrollPos( hCtrl, SB_CTL, gbVolume, FALSE );
  211.             nVolume = (short)gbVolume;
  212.  
  213.  
  214.             /* set the patch number */
  215.             SetDlgItemInt( hDlg, IDD_CFG_PATCH, gbPatch, FALSE );
  216.  
  217.  
  218.             /* I want the focus on the ok button */
  219.             SetFocus( GetDlgItem( hDlg, IDOK ) );
  220.         }
  221.         break;
  222.  
  223.         case WM_HSCROLL:
  224.             #define VOL_MIN     0
  225.             #define VOL_MAX     127
  226.             #define VOL_PAGE    15
  227.  
  228.             hCtrl = HIWORD( lParam );
  229.  
  230.             switch ( wParam )
  231.             {
  232.                 case SB_PAGEDOWN:
  233.                     nVolume += VOL_PAGE;
  234.  
  235.                     /** fall through **/
  236.  
  237.                 case SB_LINEDOWN:
  238.                     nVolume = min( VOL_MAX, nVolume + 1 );
  239.                 break;
  240.  
  241.                 case SB_PAGEUP:
  242.                     nVolume -= VOL_PAGE;
  243.  
  244.                     /** fall through **/
  245.  
  246.                 case SB_LINEUP:
  247.                     nVolume = max( VOL_MIN, nVolume - 1 );
  248.                 break;
  249.  
  250.  
  251.                 case SB_TOP:
  252.                     nVolume = VOL_MIN;
  253.                 break;
  254.  
  255.                 case SB_BOTTOM:
  256.                     nVolume = VOL_MAX;
  257.                 break;
  258.  
  259.                 case SB_THUMBPOSITION:
  260.                 case SB_THUMBTRACK:
  261.                     nVolume = LOWORD( lParam );
  262.                 break;
  263.  
  264.                 default:
  265.                     return ( FALSE );
  266.             }
  267.  
  268.             SetScrollPos( hCtrl, SB_CTL, nVolume, TRUE );
  269.             SetDlgItemInt( hDlg, IDD_CFG_VOLTEXT, nVolume, FALSE );
  270.  
  271.             return ( TRUE );
  272.         break;
  273.  
  274.         case WM_COMMAND:
  275.             switch ( wParam )
  276.             {
  277.                 case IDOK:
  278.                     /* get updated configuration stuff from controls */
  279.                     hCtrl = GetDlgItem( hDlg, IDD_CFG_CHANNEL );
  280.                     gbChannel = (BYTE)SendMessage( hCtrl, CB_GETCURSEL, 0, 0 );
  281.  
  282.                     hCtrl = GetDlgItem( hDlg, IDD_CFG_DEVICE );
  283.                     gnDevice = (BYTE)SendMessage( hCtrl, CB_GETCURSEL, 0, 0 );
  284.  
  285.                     /* assumes MIDI Mapper is dev id -1--index 0 in combo */
  286.                     gnDevice--;
  287.  
  288.                     gbVolume = (BYTE)nVolume;
  289.  
  290.                     gbPatch = (BYTE)GetDlgItemInt( hDlg, IDD_CFG_PATCH, NULL, FALSE );
  291.                     if ( gbPatch > 127 )
  292.                         gbPatch = 0;
  293.  
  294.                     /* apply changes */
  295.                     tkeybSetKeyboardParameters( ghKeyB );
  296.  
  297.                     /** fall through **/
  298.  
  299.                 case IDCANCEL:
  300.                     EndDialog( hDlg, TRUE );
  301.                     return ( TRUE );
  302.             }
  303.         break;
  304.     }
  305.  
  306.     return ( FALSE );
  307. } /* tkeybConfigDlgProc() */
  308.  
  309.  
  310. /** long FAR PASCAL tkeybWndProc( HWND, WORD, WORD, LONG )
  311.  *
  312.  *  DESCRIPTION: 
  313.  *      This is just your normal everyday WndProc().
  314.  *
  315.  *  NOTES:
  316.  *
  317.  **/
  318.  
  319. long FAR PASCAL tkeybWndProc( HWND hWnd, WORD wMsg, WORD wParam, LONG lParam )
  320. {
  321.     FARPROC lpfnDlgProc;
  322.  
  323.     switch ( wMsg ) 
  324.     {
  325.         case WM_CREATE:
  326.         {
  327.             HMENU hMenu = GetMenu( hWnd );
  328.  
  329.             CheckMenuItem( hMenu, IDM_TEST_LABELKEYS, MF_BYCOMMAND |
  330.                             (gfLabelKeys ? MF_CHECKED : MF_UNCHECKED) );
  331.  
  332.             CheckMenuItem( hMenu, IDM_TEST_HIDEOUSCOLORS, MF_BYCOMMAND |
  333.                             (gfHideousColors ? MF_CHECKED : MF_UNCHECKED) );
  334.  
  335.         }
  336.         break;
  337.  
  338.         case WM_DESTROY:
  339.             PostQuitMessage( 0 );
  340.         break;
  341.  
  342.         case WM_COMMAND:
  343.         {
  344.             switch ( wParam )
  345.             {
  346.                 case IDM_TEST_DEFAULTKEYB:
  347.                     SendMessage( GetDlgItem( hWnd, IDD_MIDIKEYB ),
  348.                                 KEYB_SETLAYOUT, TRUE, MAKELONG( 36, 48 ) );
  349.                 break;
  350.  
  351.                 case IDM_TEST_LOWHALFKEYB:
  352.                     SendMessage( GetDlgItem( hWnd, IDD_MIDIKEYB ),
  353.                                 KEYB_SETLAYOUT, TRUE, MAKELONG( 64, 0 ) );
  354.                 break;
  355.  
  356.                 case IDM_TEST_HIGHHALFKEYB:
  357.                     SendMessage( GetDlgItem( hWnd, IDD_MIDIKEYB ),
  358.                                 KEYB_SETLAYOUT, TRUE, MAKELONG( 64, 64 ) );
  359.                 break;
  360.  
  361.                 case IDM_TEST_GIANTKEYB:
  362.                     SendMessage( GetDlgItem( hWnd, IDD_MIDIKEYB ),
  363.                                  KEYB_SETLAYOUT, TRUE, MAKELONG( 96, 0 ) );
  364.                 break;
  365.  
  366.                 case IDM_TEST_LABELKEYS:
  367.                 {
  368.                     HMENU   hMenu = GetMenu( hWnd );
  369.                     HWND    hKeyBWnd = GetDlgItem( hWnd, IDD_MIDIKEYB );
  370.  
  371.                     gfLabelKeys = !gfLabelKeys;
  372.                     CheckMenuItem( hMenu, IDM_TEST_LABELKEYS, MF_BYCOMMAND |
  373.                                     (gfLabelKeys ? MF_CHECKED : MF_UNCHECKED) );
  374.  
  375.                     /* set the label style appropriately */
  376.                     lParam = GetWindowLong( hKeyBWnd, GWL_STYLE );
  377.  
  378.                     if ( gfLabelKeys )
  379.                         lParam |= KEYBS_LABELS;
  380.                     else
  381.                         lParam &= ~KEYBS_LABELS;
  382.  
  383.                     SetWindowLong( hKeyBWnd, GWL_STYLE, lParam );
  384.  
  385.                     /* force a repaint on the whole thing */
  386.                     InvalidateRect( hKeyBWnd, NULL, TRUE );
  387.                     UpdateWindow( hKeyBWnd );
  388.                 }
  389.                 break;
  390.  
  391.                 case IDM_TEST_HIDEOUSCOLORS:
  392.                 {
  393.                     HMENU   hMenu = GetMenu( hWnd );
  394.                     HWND    hKeyBWnd = GetDlgItem( hWnd, IDD_MIDIKEYB );
  395.  
  396.                     gfHideousColors = !gfHideousColors;
  397.                     CheckMenuItem( hMenu, IDM_TEST_HIDEOUSCOLORS, MF_BYCOMMAND |
  398.                                     (gfHideousColors ? MF_CHECKED : MF_UNCHECKED) );
  399.  
  400.                     /* set the colors--repaint when both are set */
  401.                     SendMessage( hKeyBWnd, KEYB_SETBKCOLOR, FALSE,
  402.                                 gfHideousColors ? RGB( 255, 0, 0 ) :
  403.                                                   RGB( 255, 255, 255 ) );
  404.  
  405.                     SendMessage( hKeyBWnd, KEYB_SETFGCOLOR, TRUE,
  406.                                 gfHideousColors ? RGB( 0, 255, 0 ) :
  407.                                                   RGB( 0, 0, 0 ) );
  408.                 }
  409.                 break;
  410.  
  411.                 case IDM_TEST_ALLNOTESOFF:
  412.                     tkeybHourGlass( TRUE );
  413.                     {
  414.                         if ( ghMidiOut )
  415.                             midiOutReset( ghMidiOut );
  416.  
  417.                         SendMessage( ghKeyB, KEYB_RESET, TRUE, 0L );
  418.                     }
  419.                     tkeybHourGlass( FALSE );
  420.                 break;
  421.  
  422.                 case IDM_TEST_CONFIGURE:
  423.                     /* standard stuff */
  424.                     lpfnDlgProc = MakeProcInstance( tkeybConfigDlgProc, ghInst );
  425.                     DialogBox( ghInst, "DLG_TESTKEYB_CONFIG", ghWnd, lpfnDlgProc );
  426.                     FreeProcInstance( lpfnDlgProc );
  427.                 break;
  428.  
  429.                 case IDM_TEST_EXIT:
  430.                     SendMessage( hWnd, WM_CLOSE, 0, 0L );
  431.                 break;
  432.  
  433.                 case IDM_HELP_ABOUT:
  434.                     /* standard stuff */
  435.                     lpfnDlgProc = MakeProcInstance( tkeybAboutDlgProc, ghInst );
  436.                     DialogBox( ghInst, "DLG_TESTKEYB_ABOUT", ghWnd, lpfnDlgProc );
  437.                     FreeProcInstance( lpfnDlgProc );
  438.                 break;
  439.             }
  440.         }
  441.         break;
  442.  
  443.         case WM_SIZE:
  444.         {
  445.             RECT    rc;
  446.  
  447.             /* resize the keyboard control to fit in parent window */
  448.             GetClientRect( hWnd, &rc );
  449.             MoveWindow( GetDlgItem( hWnd, IDD_MIDIKEYB ), 0, 0,
  450.                         rc.right - rc.left, rc.bottom - rc.top, FALSE );
  451.         }
  452.         break;
  453.  
  454.         case WM_MIDIKEYBKEYDOWN:
  455.             D( wsprintf(gachTemp, "KDOWN: %.4X:%.8lX\r\n", wParam, lParam) );
  456.             ODS( gachTemp );
  457.  
  458.             /* if the output handle is valid */
  459.             if ( wParam )
  460.                 midiOutShortMsg( wParam, lParam );
  461.         break;
  462.  
  463.         case WM_MIDIKEYBKEYUP:
  464.             D( wsprintf(gachTemp, "  KUP: %.4X:%.8lX\r\n", wParam, lParam) );
  465.             ODS( gachTemp );
  466.  
  467.             /* if the output handle is valid */
  468.             if ( wParam )
  469.                 midiOutShortMsg( wParam, lParam );
  470.         break;
  471.  
  472.         case WM_CLOSE:
  473.             DestroyWindow( hWnd );
  474.         break;
  475.  
  476.         default:
  477.             return ( DefWindowProc( hWnd, wMsg, wParam, lParam ) );
  478.     }
  479.  
  480.     return ( 0L );
  481. } /* tkeybWndProc() */
  482.  
  483.  
  484. /** BOOL NEAR PASCAL tkeybSetKeyboardParameters( HWND hKeyB )
  485.  *
  486.  *  DESCRIPTION:
  487.  *      This function sets a bunch of parameters for the keyboard control.
  488.  *
  489.  *  NOTES:
  490.  *
  491.  **/
  492.  
  493. BOOL NEAR PASCAL tkeybSetKeyboardParameters( HWND hKeyB )
  494. {
  495.     static short    nCurrentDevice = 0;
  496.     WORD            wError;
  497.  
  498.     /* has the device changed? */
  499.     if ( nCurrentDevice != gnDevice )
  500.     {
  501.         /* do we have an open device?? */
  502.         if ( ghMidiOut )
  503.         {
  504.             tkeybHourGlass( TRUE );
  505.             midiOutReset( ghMidiOut );
  506.             tkeybHourGlass( FALSE );
  507.  
  508.             if ( ghMidiOut = midiOutClose( ghMidiOut ) )
  509.             {
  510.                 MessageBox( ghWnd, "MIDI device doesn't want to close!",
  511.                             gszShortName, MB_OK );
  512.                 ghMidiOut = NULL;
  513.             }
  514.         }
  515.  
  516.         /* attempt to open the device... */
  517.         if ( wError = midiOutOpen( &ghMidiOut, gnDevice, NULL, 0L, 0L ) )
  518.         {
  519.             MessageBox( ghWnd, "Attempt to open MIDI device was most untriumphant!",
  520.                         gszShortName, MB_OK );
  521.             ghMidiOut = NULL;
  522.         }
  523.  
  524.         /* flag that we now have gnDevice open */
  525.         else nCurrentDevice = gnDevice;
  526.  
  527.         D( wsprintf( gachTemp, "ID: %d  hMidiOut: %.4Xh\r\n", gnDevice, ghMidiOut ) );
  528.         ODS( gachTemp );
  529.     }
  530.  
  531.     /* set all of the parameters */
  532.     SendMessage( hKeyB, KEYB_SETHMIDIOUT, ghMidiOut, 0L );
  533.     SendMessage( hKeyB, KEYB_SETCHANNEL, gbChannel, 0L );
  534.     SendMessage( hKeyB, KEYB_SETVELOCITY, gbVolume, 0L );
  535.  
  536.     /* now send a program change... */
  537.     if ( ghMidiOut )
  538.     {
  539.         if ( midiOutShortMsg( ghMidiOut, MAKEWORD(0xC0 + gbChannel, gbPatch) ) )
  540.         {
  541.             MessageBox( ghWnd, "Program change failed!?!", gszShortName, MB_OK );
  542.         }
  543.     }
  544.  
  545.     return ( TRUE );
  546. } /* tkeybSetKeyboardParameters() */
  547.  
  548.  
  549. /** int PASCAL WinMain( HANDLE, HANDLE, LPSTR, int )
  550.  *
  551.  *  DESCRIPTION: 
  552.  *      This is just your normal everyday WinMain() with two exceptions:
  553.  *      it calls the 'midiKeyBInit()' function to get the midiKeyB
  554.  *      class initialized.  It also crams a midiKeyB control into the
  555.  *      client area of the window.
  556.  *
  557.  *  NOTES:
  558.  *
  559.  **/
  560.  
  561. int PASCAL WinMain( HANDLE  hInstance,
  562.                     HANDLE  hPrevInstance,
  563.                     LPSTR   lpszCmdLine,
  564.                     int     nCmdShow )
  565. {
  566.     MSG         msg;
  567.     RECT        rc;
  568.     DWORD       dwStyle;
  569.  
  570.     ghInst = hInstance;
  571.  
  572.     /* only need to do this for the first instance */
  573.     if ( !hPrevInstance ) 
  574.     {
  575.         WNDCLASS    wc;
  576.  
  577.         /* initialize the midiKeyB class */
  578.         if ( !midiKeyBInit( hInstance ) )
  579.             return ( FALSE );
  580.  
  581.         wc.style         = CS_HREDRAW | CS_VREDRAW;
  582.         wc.lpfnWndProc   = tkeybWndProc;
  583.         wc.cbClsExtra    = 0;
  584.         wc.cbWndExtra    = 0;
  585.         wc.hInstance     = hInstance;
  586.         wc.hIcon         = LoadIcon( hInstance, "ICON_TESTKEYB" );
  587.         wc.hCursor       = LoadCursor( NULL, IDC_ARROW );
  588.         wc.hbrBackground = COLOR_WINDOW + 1;
  589.         wc.lpszMenuName  = "MENU_TESTKEYB";
  590.         wc.lpszClassName = gszAppName;
  591.  
  592.         if ( !RegisterClass( &wc ) )
  593.             return ( FALSE );
  594.     }
  595.  
  596.     /* open our window */
  597.     ghWnd = CreateWindow( gszAppName, gszAppName,
  598.                           WS_OVERLAPPEDWINDOW,
  599.                           CW_USEDEFAULT, CW_USEDEFAULT,
  600.                           TKEYB_WINDOW_WIDTH, TKEYB_WINDOW_HEIGHT,
  601.                           NULL, NULL, hInstance, NULL );             
  602.  
  603.     /* was the window created?? */
  604.     if ( !ghWnd )
  605.         return ( FALSE );
  606.  
  607.     /* set the style to default values */
  608.     dwStyle = WS_VISIBLE | WS_CHILD;
  609.  
  610.     if ( gfLabelKeys )
  611.         dwStyle |= KEYBS_LABELS;
  612.  
  613.     /* create the keyboard control in the parent window's client area */
  614.     GetClientRect( ghWnd, &rc );
  615.     ghKeyB = CreateWindow( gszShortName, "zYz", dwStyle,
  616.                            0, 0, rc.right, rc.bottom, ghWnd,
  617.                            IDD_MIDIKEYB, hInstance, NULL );
  618.  
  619.     /* show it */
  620.     ShowWindow( ghWnd, nCmdShow );
  621.  
  622.     /** no, we DON'T need an UpdateWindow here **/
  623.  
  624.     /* set the default keyboard state--open the MIDI Mapper */
  625.     tkeybSetKeyboardParameters( ghKeyB );
  626.  
  627.     /* the ubiquitous message dispatcher */
  628.     while ( GetMessage( &msg, NULL, 0, 0 ) )
  629.     {
  630.         TranslateMessage( &msg );
  631.         DispatchMessage( &msg );
  632.     }
  633.  
  634.     /* close current MIDI device if it is open */
  635.     if ( ghMidiOut )
  636.     {   
  637.         /* all notes off so we don't drive people nuts! */
  638.         tkeybHourGlass( TRUE );
  639.         {
  640.             /* this can take a second or two for external synths... */
  641.             midiOutReset( ghMidiOut );
  642.         }
  643.         tkeybHourGlass( FALSE );
  644.  
  645.         if ( ghMidiOut = midiOutClose( ghMidiOut ) )
  646.         {
  647.             MessageBox( ghWnd, "MIDI device doesn't want to close!",
  648.                         gszShortName, MB_OK );
  649.             ghMidiOut = NULL;
  650.         }
  651.     }
  652.  
  653.     /* vamoose */
  654.     return ( msg.wParam );
  655. } /* WinMain() */
  656.  
  657.  
  658. /** EOF: testkeyb.c **/
  659.